<script>
  {
    /*
    1.原型链继承
    优点：
      父类方法可以复用
    缺点：
      父类的所有引用属性（info）会被所有子类共享，更改一个子类的引用属性，其他子类也会受影响
      子类型实例不能给父类型构造函数传参
  */
    function Parent() {
      this.isShow = true
      this.info = {
        name: "yhd",
        age: 18,
      }
    }
    Parent.prototype.getInfo = function () {
      console.log(this.info);
    }
    function Child() { }
    function extends1(Parent, Child) {
      Child.prototype = new Parent();
    }

    extends1(Parent, Child);

    const child = new Child();
    console.log(child);


  }

  {
    /*
    2.借用父类构造函数
    优点：
      可以在子类构造函数中向父类传参数
      父类的引用属性不会被共享
    缺点：
      子类不能访问父类原型上定义的方法
  */
    function Parent() {
      this.isShow = true
      this.info = {
        name: "yhd",
        age: 18,
      }
    }
    Parent.prototype.getInfo = function () {
      console.log(this.info);
    }
    function Child() {
      Parent.apply(this, arguments);
    }


    let child1 = new Child();
    child1.info.gender = "男";
    // child1.getInfo(); // 报错，不能访问父类原型上的属性
  }

  {
    /*
   3.组合继承(原型链继承+借用父类构造函数)
    优点：
      父类的方法可以复用
      可以在Child构造函数中向Parent构造函数中传参
      父类构造函数中的引用属性不会被共享
    缺点：
      子类仍旧无法传递动态参数给父类！
      父类的构造函数被调用了两次。
  */
    function Parent() {
      this.name = 'xxx';
    }
    Parent.prototype.getName = function () {
      console.log(this.name);
    }
    function Child() {
      // 借用父类构造函数
      Parent.call(this); // 第二次执行父类构造函数
      this.age = 18;
    }
    // 原型链指向父类的实例
    Child.prototype = new Parent(); // 第一次执行父类构造函数
    Child.prototype.getAge = function () {
      console.log(this.age);
    }

    const child = new Child();
    console.log(child);
    console.log(child.getName()); // ok
    console.log(child.getAge()); // ok
  }


  {
    /*
    4.类式继承
      优点：
        父类原型属性可复用
      缺点：
        父类实例属性不会被继承
  */
    // 类似于Object.create
    function createObject(obj) {
      function F() { };
      F.prototype = obj;
      return new F();
    }
    function Parent() {
      this.name = 'parent'
    }
    Parent.prototype.getName = function () {
      console.log(this.name);
    }
    function Child() { }
    Child.prototype = createObject(Parent.prototype);
    const child = new Child();
    console.log(child);
    console.log(child.getName);
  }

  {
    /*
      5.寄生继承
      
    */
    function inherit(child, parent) {
      // 继承父类的原型
      const parentPrototype = Object.create(parent.prototype)
      // 将父类原型和子类原型合并，并赋值给子类的原型
      child.prototype = Object.assign(parentPrototype, child.prototype)
      // 重写被污染的子类的constructor
      parentPrototype.constructor = child
    }
  }

  {
    // 雅虎继承方法：
    const inherit = (function () {
      function F() { }
      return function (Target, Origin) {
        F.prototype = Origin.prototype;
        Target.prototype = new F();
        Target.prototype.constuctor = Target;
        Target.prototype.uber = Origin.prototype;
      }
    }());

    function Parent() {
      this.name = 'parent';
    }
    Parent.prototype.getName = function () {
      console.log(this.name);
    }
    function Child() {

    }
    inherit(Child, Parent);

    const child = new Child();
    console.log(child);
    console.log(child.name);
    console.log(child.getName());
  }

  {
    class Parent {
      constructor() {
        this.name = 'parent'
      }
      getName() {
        console.log(this.name);
        return this.name;
      }
    }
    class Child extends Parent {

    }
    const child = new Child();
    console.log(child);
    console.log(child.name);
    console.log(child.getName());
  }

</script>
